/*
 * enc.c
 *
 * Created: 6/13/2013 3:00:32 PM
 *  Author: Tim
 */ 

#include <avr/io.h>

//for function prototypes
#include "enc.h"

//for access to allocations
#include "../allocations.h"

#include "../dio/dio.h"

//check to see if we need to be concerned with async types.  My guess is that assigning an async type will still achieve our goal here
status_t encCheckPLOC(encInitAsync_t	*encPacket)
{
	switch (encPacket->PARAM1.PLOC)
	{
		case 0x28:
		//check to see pins D1 and D2 are free
		if(daqAlloc.dioAlloc0.dio1Alloc == FEATURE_UTILIZED || daqAlloc.dioAlloc0.dio2Alloc == FEATURE_UTILIZED)	return OPP_FAILED;
		//If the encoder is supposed to use an Index line check to see if pin D3 is free
		else if (daqAlloc.dioAlloc0.dio3Alloc == FEATURE_UTILIZED && encPacket->PARAM1.INDX)						return OPP_FAILED;
		else return OPP_SUCCESSFUL;
		break;
	
		case 0x29:
		//check to see pins D2 and D3 are free
		if(daqAlloc.dioAlloc0.dio2Alloc == FEATURE_UTILIZED || daqAlloc.dioAlloc0.dio3Alloc == FEATURE_UTILIZED)	return OPP_FAILED;
		//If the encoder is supposed to use an Index line check to see if pin D4 is free
		else if (daqAlloc.dioAlloc0.dio4Alloc && encPacket->PARAM1.INDX)											return OPP_FAILED;
		else return OPP_SUCCESSFUL;
		break;
	
		case 0x2A:
		//check to see pins D3 and D4 are free
		if(daqAlloc.dioAlloc0.dio3Alloc == FEATURE_UTILIZED || daqAlloc.dioAlloc0.dio4Alloc == FEATURE_UTILIZED)	return OPP_FAILED;
		//If the encoder is supposed to use an Index line check to see if pin D5 is free
		else if (daqAlloc.dioAlloc0.dio5Alloc && encPacket->PARAM1.INDX)											return OPP_FAILED;
		else return OPP_SUCCESSFUL;
		break;
	
		case 0x2B:
		//check to see pins D4 and D5 are free
		if(daqAlloc.dioAlloc0.dio4Alloc == FEATURE_UTILIZED || daqAlloc.dioAlloc0.dio5Alloc == FEATURE_UTILIZED)	return OPP_FAILED;
		//If the encoder is supposed to use an Index line check to see if pin D6 is free
		else if (daqAlloc.dioAlloc0.dio6Alloc && encPacket->PARAM1.INDX)											return OPP_FAILED;
		else return OPP_SUCCESSFUL;
		break;
	
		case 0x2C:
		//check to see pins D5 and D6 are free
		if(daqAlloc.dioAlloc0.dio5Alloc == FEATURE_UTILIZED || daqAlloc.dioAlloc0.dio6Alloc == FEATURE_UTILIZED)	return OPP_FAILED;
		//If the encoder is supposed to use an Index, return an error.
		//There is no third sequential pin available starting and encoder interface from pin D5
		else if (encPacket->PARAM1.INDX)																			return OPP_FAILED;
		else return OPP_SUCCESSFUL;
		break;
	
	
	
		case 0x30:
		//check to see pins D12 and D11 are free
		if(daqAlloc.dioAlloc1.dio12Alloc == FEATURE_UTILIZED || daqAlloc.dioAlloc1.dio11Alloc == FEATURE_UTILIZED)	return OPP_FAILED;
		//If the encoder is supposed to use an Index line check to see if pin D10 is free
		else if (daqAlloc.dioAlloc1.dio10Alloc && encPacket->PARAM1.INDX)											return OPP_FAILED;
		else return OPP_SUCCESSFUL;
		break;
		case 0x31:
		//check to see pins D11 and D10 are free
		if(daqAlloc.dioAlloc1.dio11Alloc == FEATURE_UTILIZED || daqAlloc.dioAlloc1.dio10Alloc == FEATURE_UTILIZED)	return OPP_FAILED;
		//If the encoder is supposed to use an Index line check to see if pin D9 is free
		else if (daqAlloc.dioAlloc1.dio9Alloc && encPacket->PARAM1.INDX)											return OPP_FAILED;
		else return OPP_SUCCESSFUL;
		break;
		case 0x32:
		//check to see pins D10 and D9 are free
		if(daqAlloc.dioAlloc1.dio10Alloc == FEATURE_UTILIZED || daqAlloc.dioAlloc1.dio9Alloc == FEATURE_UTILIZED)	return OPP_FAILED;
		//If the encoder is supposed to use an Index, return an error.
		//There is no third sequential pin available starting and encoder interface from pin D10
		else if (encPacket->PARAM1.INDX)																			return OPP_FAILED;
		else return OPP_SUCCESSFUL;
		break;
	}
	
	return OPP_FAILED;
}
//This function should be called once it has been determined that
//1) The pins for the encoder interface are available
//2) There a timer/counter available for the interface 

void encSetup(encInitAsync_t *encPacket, tmrAlloc_t encTmr)
{

//This section sets the allocations of the digital pins	
	switch (encPacket->PARAM1.PLOC)
	{
		case 0x28:
		if (encPacket->PARAM1.INDX)
		{
			dioDirClr(1);
			dioSense(PORT_ISC_LEVEL_gc,1);
			dioDirClr(2);
			dioSense(PORT_ISC_LEVEL_gc,2);
			dioDirClr(3);
			dioSense(PORT_ISC_LEVEL_gc,3);
			
			daqAlloc.dioAlloc0.dio1Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc0.dio2Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc0.dio3Alloc	= FEATURE_UTILIZED;
		}
		else
		{
			dioDirClr(1);
			dioSense(PORT_ISC_LEVEL_gc,1);
			dioDirClr(2);
			dioSense(PORT_ISC_LEVEL_gc,2);
			daqAlloc.dioAlloc0.dio1Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc0.dio2Alloc	= FEATURE_UTILIZED;
		}
		break;
		
		case 0x29:
		if (encPacket->PARAM1.INDX)
		{
			dioDirClr(2);
			dioSense(PORT_ISC_LEVEL_gc,2);
			dioDirClr(3);
			dioSense(PORT_ISC_LEVEL_gc,3);
			dioDirClr(4);
			dioSense(PORT_ISC_LEVEL_gc,4);
			
			daqAlloc.dioAlloc0.dio2Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc0.dio3Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc0.dio4Alloc	= FEATURE_UTILIZED;
		}
		else
		{
			dioDirClr(2);
			dioSense(PORT_ISC_LEVEL_gc,2);
			dioDirClr(3);
			dioSense(PORT_ISC_LEVEL_gc,3);
			
			daqAlloc.dioAlloc0.dio2Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc0.dio3Alloc	= FEATURE_UTILIZED;
		}
		break;
		
		case 0x2A:
		if (encPacket->PARAM1.INDX)
		{
			dioDirClr(3);
			dioSense(PORT_ISC_LEVEL_gc,3);
			dioDirClr(4);
			dioSense(PORT_ISC_LEVEL_gc,4);
			dioDirClr(5);
			dioSense(PORT_ISC_LEVEL_gc,5);
			
			daqAlloc.dioAlloc0.dio3Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc0.dio4Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc0.dio5Alloc	= FEATURE_UTILIZED;
		}
		else
		{
			dioDirClr(3);
			dioSense(PORT_ISC_LEVEL_gc,3);
			dioDirClr(4);
			dioSense(PORT_ISC_LEVEL_gc,4);
			
			daqAlloc.dioAlloc0.dio3Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc0.dio4Alloc	= FEATURE_UTILIZED;
		}
		break;
		
		case 0x2B:
		if (encPacket->PARAM1.INDX)
		{
			dioDirClr(4);
			dioSense(PORT_ISC_LEVEL_gc,4);
			dioDirClr(5);
			dioSense(PORT_ISC_LEVEL_gc,5);
			dioDirClr(6);
			dioSense(PORT_ISC_LEVEL_gc,6);
			
			daqAlloc.dioAlloc0.dio4Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc0.dio5Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc0.dio6Alloc	= FEATURE_UTILIZED;
		}
		else
		{
			dioDirClr(4);
			dioSense(PORT_ISC_LEVEL_gc,4);
			dioDirClr(5);
			dioSense(PORT_ISC_LEVEL_gc,5);
			
			daqAlloc.dioAlloc0.dio4Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc0.dio5Alloc	= FEATURE_UTILIZED;
		}
		break;
		
		case 0x2C:
			dioDirClr(5);
			dioSense(PORT_ISC_LEVEL_gc,5);
			dioDirClr(6);
			dioSense(PORT_ISC_LEVEL_gc,6);
			
			daqAlloc.dioAlloc0.dio5Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc0.dio6Alloc	= FEATURE_UTILIZED;
		break;
		
		
		
		case 0x30:
		if (encPacket->PARAM1.INDX)
		{
			dioDirClr(12);
			dioSense(PORT_ISC_LEVEL_gc,12);
			dioDirClr(11);
			dioSense(PORT_ISC_LEVEL_gc,11);
			dioDirClr(10);
			dioSense(PORT_ISC_LEVEL_gc,10);
			daqAlloc.dioAlloc1.dio12Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc1.dio11Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc1.dio10Alloc	= FEATURE_UTILIZED;
		}
		else
		{
			dioDirClr(12);
			dioSense(PORT_ISC_LEVEL_gc,12);
			dioDirClr(11);
			dioSense(PORT_ISC_LEVEL_gc,11);
			
			daqAlloc.dioAlloc1.dio12Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc1.dio11Alloc	= FEATURE_UTILIZED;
		}
		break;
		case 0x31:
		if (encPacket->PARAM1.INDX)
		{
			dioDirClr(11);
			dioSense(PORT_ISC_LEVEL_gc,11);
			dioDirClr(10);
			dioSense(PORT_ISC_LEVEL_gc,10);
			dioDirClr(9);
			dioSense(PORT_ISC_LEVEL_gc,9);
			
			daqAlloc.dioAlloc1.dio11Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc1.dio10Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc1.dio9Alloc	= FEATURE_UTILIZED;
		}
		else
		{
			dioDirClr(11);
			dioSense(PORT_ISC_LEVEL_gc,11);
			dioDirClr(10);
			dioSense(PORT_ISC_LEVEL_gc,10);
			
			daqAlloc.dioAlloc1.dio11Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc1.dio10Alloc	= FEATURE_UTILIZED;
		}
		break;
		case 0x32:
			dioDirClr(10);
			dioSense(PORT_ISC_LEVEL_gc,10);
			dioDirClr(9);
			dioSense(PORT_ISC_LEVEL_gc,9);
			
			daqAlloc.dioAlloc1.dio10Alloc	= FEATURE_UTILIZED;
			daqAlloc.dioAlloc1.dio9Alloc	= FEATURE_UTILIZED;
		break;
	}

	//this section sets up the Event system for QDEC
	
	if		(encPacket->PARAM1.ENCN)
	{
		//configure the encoder pin location
		EVSYS.CH4MUX = 0x40 | encPacket->PARAM1.PLOC;
			
		//Encoder 0 enable and parameters
		EVSYS.CH4CTRL =	(encPacket->PARAM1.INDX<<EVSYS_QDIEN_bp) |		//enable index line if one is specified
		EVSYS_QDEN_bm |													//enable encoder interface
		(encPacket->PARAM2.EDFL<<EVSYS_DIGFILT0_bp);					//set the digital filter depth
		daqAlloc.encAlloc.enc1TmrAlloc = encTmr;
		if(encPacket->PARAM2.ABS) daqAlloc.encAlloc.enc1Abs = FEATURE_UTILIZED;
		
	}
	else
	{
		//configure the encoder pin location
		EVSYS.CH2MUX = 0x40 | encPacket->PARAM1.PLOC;
			
		//Encoder 1 enable and parameters
		EVSYS.CH2CTRL =	(encPacket->PARAM1.INDX<<EVSYS_QDIEN_bp) |		//enable index line if one is specified
		EVSYS_QDEN_bm |													//enable encoder interface
		(encPacket->PARAM2.EDFL<<EVSYS_DIGFILT0_bp);					//set the digital filter depth
		daqAlloc.encAlloc.enc0TmrAlloc = encTmr;
		if(encPacket->PARAM2.ABS) daqAlloc.encAlloc.enc0Abs = FEATURE_UTILIZED;
	}
	
	switch(encTmr)
	{
		case TIMER_C0:
			//Enable timer for QDEC via channel 2 of the event sysem
			if(encPacket->PARAM1.ENCN)	TCC0.CTRLD =	TC_EVACT_QDEC_gc | TC_EVSEL_CH4_gc;
			//Enable timer for QDEC via channel 4 of the event sysem	
			else						TCC0.CTRLD =	TC_EVACT_QDEC_gc | TC_EVSEL_CH2_gc;	
			//set the counter depth to 4x the encoder resolution
			TCC0.CTRLA = TC_CLKSEL_DIV1_gc;
			TCC0.PER = ((encPacket->PARAM2.ERESH<<8) | encPacket->PARAM3.ERESL)<<2;
			daqAlloc.timerAlloc.timerC0Alloc = FEATURE_UTILIZED;
		break;
		case TIMER_C1:
			//Enable timer for QDEC via channel 2 of the event system
			if(encPacket->PARAM1.ENCN)	TCC1.CTRLD =	TC_EVACT_QDEC_gc | TC_EVSEL_CH4_gc;
			//Enable timer for QDEC via channel 4 of the event system
			else						TCC1.CTRLD =	TC_EVACT_QDEC_gc | TC_EVSEL_CH2_gc;
			//set the counter depth to 4x the encoder resolution
			TCC1.PER = ((encPacket->PARAM2.ERESH<<8) | encPacket->PARAM3.ERESL)<<2;
			daqAlloc.timerAlloc.timerC1Alloc = FEATURE_UTILIZED;
		break;
		case TIMER_D0:
			//Enable timer for QDEC via channel 2 of the event system
			if(encPacket->PARAM1.ENCN)	TCD0.CTRLD =	TC_EVACT_QDEC_gc | TC_EVSEL_CH4_gc;
			//Enable timer for QDEC via channel 4 of the event sysem
			else						TCD0.CTRLD =	TC_EVACT_QDEC_gc | TC_EVSEL_CH2_gc;
			//set the counter depth to 4x the encoder resolution
			TCD0.CTRLA = TC_CLKSEL_DIV1_gc;
			TCD0.PER = ((encPacket->PARAM2.ERESH<<8) | encPacket->PARAM3.ERESL)<<2;
			daqAlloc.timerAlloc.timerD0Alloc = FEATURE_UTILIZED;
		break;
		case TIMER_D1:
			//Enable timer for QDEC via channel 2 of the event system
			if(encPacket->PARAM1.ENCN)	TCD1.CTRLD =	TC_EVACT_QDEC_gc | TC_EVSEL_CH4_gc;
			//Enable timer for QDEC via channel 4 of the event system
			else						TCD1.CTRLD =	TC_EVACT_QDEC_gc | TC_EVSEL_CH2_gc;
			//set the counter depth to 4x the encoder resolution
			TCD1.CTRLA = TC_CLKSEL_DIV1_gc;
			TCD1.PER = ((encPacket->PARAM2.ERESH<<8) | encPacket->PARAM3.ERESL)<<2;
			daqAlloc.timerAlloc.timerD1Alloc = FEATURE_UTILIZED;
		break;
		case TIMER_E0:
			//Enable timer for QDEC via channel 2 of the event system
			if(encPacket->PARAM1.ENCN)	TCE0.CTRLD =	TC_EVACT_QDEC_gc | TC_EVSEL_CH4_gc;
			//Enable timer for QDEC via channel 4 of the event system
			else						TCE0.CTRLD =	TC_EVACT_QDEC_gc | TC_EVSEL_CH2_gc;
			//set the counter depth to 4x the encoder resolution
			TCE0.CTRLA = TC_CLKSEL_DIV1_gc;
			TCE0.PER = ((encPacket->PARAM2.ERESH<<8) | encPacket->PARAM3.ERESL)<<2;
			daqAlloc.timerAlloc.timerE0Alloc = FEATURE_UTILIZED;
		break;
		case TIMER_NULL:										
			//This condition should never occur
			//Timer allocation should have been
			//checked prior to calling encSetup
		break;
		
	}
	
}



